# -*- coding: utf-8 -*-
'''
@File    :   checksum.py
@Time    :   2024/08/18 08:08:05
@Author  :   string
@Version :   1.0
@Desc    :   实现常用的校验算法
'''

import typing
from enum import Enum

import crc


class CRCType(Enum):
    XCP_CRC_16 = 0x00
    XCP_CRC16_CITT = 0x01
    XCP_CRC_32 = 0x02
    
def reverse_bits(data:int, bit_len:int) -> int:
    if (bit_len == 16):
        data = (data & 0xAAAA) >> 1 | (data & 0x5555) << 1
        data = (data & 0xCCCC) >> 2 | (data & 0x3333) << 2
        data = (data & 0xF0F0) >> 4 | (data & 0x0F0F) << 4
        data = (data & 0xFF00) >> 8 | (data & 0x00FF) << 8
        return data
    if (bit_len == 8):
        data = (data & 0xAA) >> 1 | (data & 0x55) << 1
        data = (data & 0xCC) >> 2 | (data & 0x33) << 2
        data = (data & 0xF0) >> 4 | (data & 0x0F) << 4
        return data
    raise ValueError("bit_len error")

def _crc_cal_by_shift(width:int,polynomial:int, reflect_in:bool, reflect_out:bool, init_value:int, xor_out:int, data:typing.List[int]) -> int:
    # res = 0
    check_bit: int = 0x01 << (width - 1)
    for i in range(len(data)):
        # 判断是否在开始反转
        if (reflect_in):
            data[i] = reverse_bits(data[i], width)
            
        # 移位处理
        for j in range(width):
            if (data[i] & check_bit):
                data[i] = (data[i] << 1) ^ polynomial
            else:
                data[i] = data[i] << 1
        
        # 判断是否在结束反转
        if (reflect_out):
            data[i] = reverse_bits(data[i], width)
        
    return data[-1] ^ xor_out

def crc_cal(crc_type:CRCType, list_data:list) -> int:
    if (crc_type == CRCType.XCP_CRC_16):
        res = _crc_cal_by_shift(16, 0x8005, True, True, 0x0000, 0x0000, list_data)
        return res
        pass
    elif (crc_type == CRCType.XCP_CRC16_CITT):
        raise NotImplementedError("CRC16_CITT not implemented")
        pass
    elif (crc_type == CRCType.XCP_CRC_32):
        # raise NotImplementedError("CRC32 not implemented")
        data = bytes(list_data)
        calculator = crc.Calculator(crc.Crc32.CRC32)
        res = calculator.checksum(data)
        return res
        pass
    else:
        raise ValueError("crc_type error")
    res = 0x00
    return res



